/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package domain.player.ai;

import domain.GameGrid;
import domain.player.Disc;
import java.util.*;
import techniqcalServices.ObjectFileIO;

/**
 * saves the moves of the opponent and "re-plays" them in the same situation(when the gamegrid looks
 * as it did when the move were saved).
 */
public class AI_HashMap extends AI {

    private GameGrid prevGrid;
    private Map<String, Integer> savedMoves; //  = new HashMap<String, GameGrid>(); ?
    private String filename = "src/image/hashMap.dat";
    private ObjectFileIO mapFile;

    public AI_HashMap(Disc discID) {
	super(discID);
	mapFile = new ObjectFileIO(filename);
	prevGrid = new GameGrid(null);
	prevGrid.resetGameGrid();
	savedMoves = (HashMap<String, Integer>)mapFile.readFile();
	if(savedMoves == null){
	    savedMoves = new HashMap<String, Integer>();
	}
    }

    @Override
    public int getType() {
	return AI.AI_HASHMAP;
    }


    /* returns a move decided from the GameGrid grid */
    @Override
    public int getGoodMove(GameGrid grid) {

	int move = 0;

	saveMove(prevGrid, grid);
	prevGrid.copyFromGrid(grid);
	move = getMove(grid);
	prevGrid.setDisc(move, super.getDiscID());
	printHashMap();
	return move;


    }

    /* saves the move to the HashMap and the HashMap file*/
    private void saveMove(GameGrid prev, GameGrid cur) {
	// remove the && savedMoves.get(prev.toString()) == null to always save the latest move and
	// overwrite the old one on that column
	if (!cur.isEmpty() && savedMoves.get(prev.toString()) == null) {
	    int move = columnThatDiffer(prev, cur);
	    savedMoves.put(prev.toString(), move);
	    savedMoves.put(prev.reversedGameGrid().toString(), move);
	    mapFile.saveFiles(savedMoves);
	}
    }

    /* gets a move from the computer, if there is one stored in the HashMap that move is returned
     * if there are no move stored for this particular grid setup a move returned by searchForWinningMove
     * is returned.
     */
    private int getMove(GameGrid cur) {
	int move = 0;
	GameGrid reversed = cur.reversedGameGrid();



	if (savedMoves.get(cur.toString()) != null) {
	    move = savedMoves.get(cur.toString());
	} else if (savedMoves.get(reversed.toString()) != null) {
	    move = savedMoves.get(reversed.toString());
	} else {
	    move = searchForWinningMove(cur);
	    savedMoves.put(cur.toString(), move);
	}
	return move;
    }


    /*searches for a good move and if there are none it returns a random valued one */
    private int searchForWinningMove(GameGrid cur) {
	GameGrid tempGrid = new GameGrid(null);
	tempGrid.copyFromGrid(cur);
	for (int i = 0; i < GameGrid.GRID_COLUMNS; i++) {
	    if (tempGrid.isValidMove(i) && isWinningMove(i, getDiscID())) {
		return i;
	    }
	}
	// searches for the opponents winning moves.
	Disc opponentColor = (getDiscID() == Disc.ONE ? Disc.TWO : Disc.ONE);
	for (int i = 0; i < GameGrid.GRID_COLUMNS; i++) {
	    if (tempGrid.isValidMove(i) && isWinningMove(i, opponentColor)) {
		System.out.println("Column " + i + " should be blocked.");
		return i;
	    }
	}

	// no good moves found, pick a move at random.
	System.out.println("Random move!");
	int i = pickRandomColumn(cur);
	return i;

    }

    /**
     * isWinningMove requires a legal move/column.
     */
    private boolean isWinningMove(int column, Disc color) {
	int row;
	boolean winningMove;

	row = prevGrid.setDisc(column, color);
	winningMove = prevGrid.winningMove(row, column);
	prevGrid.removeDisc(row, column);

	return winningMove;
    }

    /* returns the opposite disc of the Disc disc */
    private Disc oppositeDisc(Disc disc) {
	if (disc == disc.NONE) {
	    return disc.NONE;
	} else {
	    return disc == disc.ONE ? disc.TWO : disc.ONE;
	}

    }


    /* returns the column that differ between the two GameGrids prev and cur, assuming that it is only one */
    private int columnThatDiffer(GameGrid prev, GameGrid cur) {
	for (int i = GameGrid.GRID_ROWS - 1; i >= 0; i--) {
	    for (int j = GameGrid.GRID_COLUMNS - 1; j >= 0; j--) {
		if (prev.getDisc(i, j) != cur.getDisc(i, j)) {
		    //System.out.println("column that differ " + j + " on grids " + prev.toString() + " and " + cur.toString());
		    return j;
		}
	    }
	}
	System.out.println("could not find column that differ returns an random value ");
	return pickRandomColumn(prev);
    }

    // a method to print the current hashmap
    private void printHashMap() {

	Set set = savedMoves.entrySet();

	Iterator i = set.iterator();

	while (i.hasNext()) {
	    Map.Entry me = (Map.Entry) i.next();
	    System.out.println("key" + me.getKey() + "\nvalue " + me.getValue());
	}
    }
}
